
package SSF.OS.UDP.test;

/**
 * udpStreamSession.java
 * Author: ato
 *
 */

import SSF.OS.*;
import SSF.OS.Socket.*;
import SSF.OS.UDP.*;
import SSF.OS.UDP.test.*;
import SSF.Net.*;
import SSF.Net.Util.*;
import com.renesys.raceway.DML.*;
import java.util.*;

/** Class executing a single client-server session. */
public class udpStreamSession extends ProtocolSession {

  /************************* Class Variables *********************/

  /** client who created this session */
  udpStreamClient owner;

  /** client-assigned session id */
  int id;

  /** client's Continuation for this session */
  Continuation clientCont;

  /** print out debug information */
  boolean showDebug;

  /** print out summary session report */
  boolean showReport;

  /** size (in bytes) of request datagram sent from client to server */
  int requestSize;

  /** requested file size */
  long fileSize;

  /** size (in bytes) of datagrams received from servers */
  int srvDatagramSize;

  /** Host entity where this pseudo-protocol is installed */
  Host localHost;

  /** local socket used by this session */
  socketAPI sd;

  private String srvNHI;    
  private int srvIP;
  private int srvPort;

  private String locNHI;
  private int locIP;
  private int locPort;
  private long dataReceived = 0L;
  private String str;
  private long startTime;

  /************************* Constructors ************************/

  public udpStreamSession (udpStreamClient client, int sessid,
                           udpStreamClient.serverData serv, long file_size) {
    owner = client;
    localHost = client.localHost;
    id = sessid;
    locNHI = client.localNHI;
    locIP = client.localIP;

    requestSize = client.request_size;
    fileSize = client.file_size;
    showReport = client.show_report;
    showDebug = client.debug;

    srvNHI = serv.nhi;
    srvIP  = serv.ip;
    srvPort = serv.port;
    srvDatagramSize = client.datagram_size;
  }

  /************************* Class Methods ***********************/

  public void begin() {
    startTime = localHost.now();
    try { 
      sd = owner.sockms.socket(this, "udp");
      locPort = owner.sockms.getPortNumber();
      sd.bind(locIP, locPort);
      sd.connect(srvIP, srvPort, null);  //nonblocking
    }
    catch (ProtocolException e) { System.err.println(e); }
    sendRequest();
  }

  public void begin(Continuation caller) {
    clientCont = caller;
    begin();
  }

  // what happens if request datagram is lost - no provision for this.
  void sendRequest() {
    Object[] obj = new Object[1];
    obj[0] = new Integer((int)fileSize); 
    sd.write(obj, requestSize, new Continuation() {
      public void success() {
        if (showDebug) {
          str = "request " + fileSize + "B" + " to " + srvNHI + " OK";
          clientDebug(str);
        }
        readData();
      }
      public void failure(int errno) {
        if (showDebug) {
          str = "request " + " to " + srvNHI + " FAILED";
          clientDebug(str);
        } 
      }
    });
  }

  // we read data one message at a time
  void readData() {
    sd.read(srvDatagramSize, new Continuation() {
      public void success() {
        if(showDebug) {
          str = "read() " + srvDatagramSize + "B";
          clientDebug(str);
        }
        dataReceived += srvDatagramSize;
        if(fileSize <= dataReceived) {
          if(showReport || showDebug) {
            double duration = (localHost.now() -
                              startTime)/(double)SSF.Net.Net.seconds(1.0);
            str = "rcvd " + fileSize + "B at "
                  +  ((long)(8*fileSize/duration))/1000.0
                  + "kbps - read() SUCCESS ";
            sessionReport(str);
          }
          try {
            sd.close(null); //nonblocking
          } catch (ProtocolException e) {
              System.err.println(e);
          }
          if (showDebug)
            clientDebug("close()");
          if(clientCont != null)
            clientCont.success();
        }else {
          readData();
        }
      }
      public void failure(int errno) {
        if (showDebug) 
          clientDebug(" read() FAILURE ");
      }
    });
  }

  /** preamble to client-side-only diagnostics */
  public void clientDebug(String str){
    System.err.println(localHost.now()/(double)SSF.Net.Net.seconds(1.0)
                       + " clnt " + locNHI 
                       + " " + IP_s.IPtoString(locIP) + ":" + locPort
                       + " sid " + id + " " + str);
  }

  /** preamble to end2end session diagnostics */
  public void sessionReport(String str){
    System.err.println(localHost.now()/(double)SSF.Net.Net.seconds(1.0)
            + " [ sid " + id + " start " 
            + startTime/(double)SSF.Net.Net.seconds(1.0) 
            + " ] clnt " + locNHI
            + " srv " + srvNHI + " " + str);
  }

  public boolean push(ProtocolMessage message, ProtocolSession fromSession)
    throws ProtocolException {
    return false;
  }
}
